/**
 * @ Author: luoqi
 * @ Create Time: 2024-07-17 11:39
 * @ Modified by: luoqi
 * @ Modified time: 2024-07-17 22:09
 * @ Description:
 */

#include "ringbuf.h"

static void *_memcpy(void *dst, void *src, uint32_t len)
{
    char *d;
    const char *s;
    if(((uint32_t)dst > ((uint32_t)src + len)) || (dst < src)){
        d = dst;
        s = src;
        while(len --){
            *d++ = *s++;
        }
    }else{
        d = (char *)((uint32_t)dst + len - 1);
        s = (char *)((uint32_t)src + len - 1);
        while(len --){
            *d-- = *s--;
        }
    }
    return dst;
}

int ringbuf_init(RingBufObj *ring, uint8_t *buf, uint32_t size)
{
    ring->r_index = 0;
    ring->w_index = 0;
    ring->msgsz = 0;
    ring->bufsz = size;
    ring->buf = buf;
    return 0;
}

uint32_t ringbuf_write_covern(RingBufObj *ring, uint8_t *data, uint32_t len)
{
    if(ring->bufsz < len){
        len = ring->bufsz;
    }
    
    if(ring->w_index >= ring->r_index){
        ring->msgsz = ring->w_index - ring->r_index;
    }else{
        ring->msgsz = (ring->bufsz - ring->r_index) + ring->w_index;
    }

    if((ring->w_index + len) > ring->bufsz){
        _memcpy(ring->buf + ring->w_index, data, ring->bufsz - ring->w_index);
        _memcpy(ring->buf, data + (ring->bufsz - ring->w_index), len - (ring->bufsz - ring->w_index));
    }else{
        _memcpy(ring->buf + ring->w_index, data, len);
    }
    ring->msgsz = ring->msgsz + len;
    ring->w_index = (ring->w_index + len) % ring->bufsz;
    return ring->w_index;
}

int ringbuf_write(RingBufObj *ring, uint8_t *data, uint32_t len)
{
    if(ring->bufsz <= ring->msgsz){
        return -1;
    }else if(ring->w_index >= ring->r_index){
        ring->msgsz = ring->w_index - ring->r_index;
    }else{
        ring->msgsz = (ring->bufsz - ring->r_index) + ring->w_index;
    }
    
    if((ring->bufsz - ring->msgsz) < len){
        return -1;
    }else if((ring->w_index + len) > ring->bufsz){
        _memcpy(ring->buf + ring->w_index, data, ring->bufsz - ring->w_index);
        _memcpy(ring->buf, data + (ring->bufsz - ring->w_index), len - (ring->bufsz - ring->w_index));
    }else{
        _memcpy(ring->buf + ring->w_index, data, len);
    }
    ring->msgsz = ring->msgsz + len;
    ring->w_index = (ring->w_index + len) % ring->bufsz;
    return ring->w_index;
}

uint32_t ringbuf_read(RingBufObj *ring, uint8_t *rdata, uint32_t len)
{
    if(ring->msgsz < len){
        len = ring->msgsz;
    }
    if(ring->w_index >= ring->r_index){
        _memcpy(rdata, ring->buf + ring->r_index, len);
    }else {
        if((ring->bufsz - ring->r_index) >= len){
            _memcpy(rdata, ring->buf + ring->r_index, len);
        }else{
            _memcpy(rdata, ring->buf + ring->r_index, ring->bufsz - ring->r_index);
            _memcpy(rdata + (ring->bufsz - ring->r_index), ring->buf, len - (ring->bufsz - ring->r_index));      
        }
    }
    ring->msgsz = ring->msgsz - len;
    ring->r_index = (ring->r_index + len) % ring->bufsz;
    return len;
}

uint32_t ringbuf_get_size(RingBufObj *ring)
{
    return ring->msgsz;
}

void ringbuf_clear(RingBufObj *ring)
{
    ring->w_index = 0;
    ring->r_index = 0;
    ring->msgsz = 0;
}
